
package com.xjh.t.controller;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.Callback;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.tomcat.util.buf.StringUtils;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URI;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Map;


import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * TODO
 *
 * @author <a href="imiros@163.com">hm</a>
 * @version 1.0.0, 05-29-2019
 */
@RestController
@RequestMapping("oss")
@SuppressWarnings(value={"all"})
public class OssController {

    static final Logger logger = LoggerFactory.getLogger(OssController.class);
    static final String endpoint = "sts.cn-hangzhou.aliyuncs.com";
    static final String accessKeyId = "";
    static final String accessKeySecret = "";
    static final String roleArn = "";
    static final String roleSessionName = "";
    //以上账号信息请使用自己的阿里云相关信息。

    @RequestMapping("getToken")
    public String getToken() {
        JSONObject jsonObject = new JSONObject();
        String policy = "{\n" +
                "    \"Version\": \"1\", \n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:*\"\n" +
                "            ], \n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:*\" \n" +
                "            ], \n" +
                "            \"Effect\": \"Allow\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        try {
            // 添加endpoint（直接使用STS endpoint，前两个参数留空，无需添加region ID）
            DefaultProfile.addEndpoint("", "", "Sts", endpoint);
            // 构造default profile（参数留空，无需添加region ID）
            IClientProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret);
            // 用profile构造client
            DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleSessionName);
            // Optional
            request.setPolicy(policy);
            final AssumeRoleResponse response = client.getAcsResponse(request);
            jsonObject.put("Expiration", response.getCredentials().getExpiration());
            jsonObject.put("AccessKeyId", response.getCredentials().getAccessKeyId());
            jsonObject.put("AccessKeySecret", response.getCredentials().getAccessKeySecret());
            jsonObject.put("SecurityToken", response.getCredentials().getSecurityToken());
            jsonObject.put("StatusCode", "200");
            System.out.println(response.getCredentials());
        } catch (ClientException e) {
            jsonObject.put("ErrorCode", e.getErrCode());
            jsonObject.put("StatusCode", "500");
            jsonObject.put("ErrorMessage", e.getErrMsg());
        }
        logger.info("获取OSS的STS凭证响应信息 : " + jsonObject.toString());
        return jsonObject.toString();
    }

    @RequestMapping(value = "callback")
    public String upload(HttpServletRequest request, String filename) {
        String ossCallbackBody = "";
        JSONObject jsonObject = new JSONObject();
        Map<String, String[]> map = request.getParameterMap();
        if (map.size() != 0) {
            for (String key : map.keySet()) {
                ossCallbackBody += key + "=" + StringUtils.join(map.get(key)) + "&";
            }
            ossCallbackBody = ossCallbackBody.substring(0, ossCallbackBody.length() - 1);
        }
        logger.info("ossCallbackBody：" + ossCallbackBody);
        boolean ret = VerifyOSSCallbackRequest(request, ossCallbackBody);
        if (ret) {
            jsonObject.put("filename", filename);
            jsonObject.put("Status", "OK");
        } else {
            jsonObject.put("Status", "verify not ok");
        }
        logger.info("OSS的回调响应 :" + jsonObject.toString());
        return jsonObject.toString();
    }

    protected boolean VerifyOSSCallbackRequest(HttpServletRequest request, String ossCallbackBody) {
        boolean ret = false;
        String autorizationInput = new String(request.getHeader("Authorization"));
        String pubKeyInput = request.getHeader("x-oss-pub-key-url");
        byte[] authorization = BinaryUtil.fromBase64String(autorizationInput);
        byte[] pubKey = BinaryUtil.fromBase64String(pubKeyInput);
        String pubKeyAddr = new String(pubKey);
        if (!pubKeyAddr.startsWith("http://gosspublic.alicdn.com/") && !pubKeyAddr
                .startsWith("https://gosspublic.alicdn.com/")) {
            System.out.println("pub key addr must be oss addrss");
            return false;
        }
        String retString = executeGet(pubKeyAddr);
        retString = retString.replace("-----BEGIN PUBLIC KEY-----", "");
        retString = retString.replace("-----END PUBLIC KEY-----", "");
        String queryString = request.getQueryString();
        String uri = request.getRequestURI();
        String decodeUri = null;
        try {
            decodeUri = java.net.URLDecoder.decode(uri, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        String authStr = decodeUri;
        if (queryString != null && !queryString.equals("")) {
            authStr += "?" + queryString;
        }
        authStr += "\n" + ossCallbackBody;
        ret = doCheck(authStr, authorization, retString);
        logger.info("------authStr:" + authStr);
        logger.info("------pubKeyAddr:" + pubKeyAddr);
        logger.info("------authorization:" + authorization);
        logger.info("------retString:" + retString);
        return ret;
    }

    public String executeGet(String url) {
        BufferedReader in = null;

        String content = null;
        try {
            // 定义HttpClient
            @SuppressWarnings("resource")
            DefaultHttpClient client = new DefaultHttpClient();
            // 实例化HTTP方法
            HttpGet request = new HttpGet();
            request.setURI(new URI(url));
            HttpResponse response = client.execute(request);

            in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            StringBuffer sb = new StringBuffer("");
            String line = "";
            String NL = System.getProperty("line.separator");
            while ((line = in.readLine()) != null) {
                sb.append(line + NL);
            }
            in.close();
            content = sb.toString();
        } catch (Exception e) {
        } finally {
            if (in != null) {
                try {
                    in.close();// 最后要关闭BufferedReader
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return content;
        }
    }

    public static boolean doCheck(String content, byte[] sign, String publicKey) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            byte[] encodedKey = BinaryUtil.fromBase64String(publicKey);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
            java.security.Signature signature = java.security.Signature.getInstance("MD5withRSA");
            signature.initVerify(pubKey);
            signature.update(content.getBytes());
            boolean bverify = signature.verify(sign);
            return bverify;

        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    @RequestMapping(value = "/doFileUpload",method = RequestMethod.POST)
    public Map<String,Object> doFileUpload(HttpServletRequest request,
                                           HttpServletResponse reponse,
                                           @RequestParam("file") MultipartFile srcFile) throws IOException{

        /*
         * 注意:传入参数时，文件的注解@ReuqestParam("variable") -->variable指:前端的h5的控件的name值.
         *
         * 文件处理功能: 1.将获取的字节数组转化为文件对象，并保存在本地目录中;
         *
         * 文件处理思路: 1.将获取的(source)file对象，通过函数获取字节数组；
         * 				2.实例化文件对象和文件输出流；
         * 				3.将字节数组写入文件即可.
         *
         * 功能难度: 简单.
         */

        //1.变量声明
        Map<String,Object> result = null;// 返回结果变量
        FileOutputStream fos = null; 	//写入文件的变量
        File destFile = null;	//写入的目的地文件(distination)

        try {
            result = new HashMap<String,Object>();

            //2.参数验证
            if(srcFile == null){
                throw new RuntimeException("上传文件不存在");
            }
            if(srcFile.getBytes().length == 0){
                throw new RuntimeException("上传文件内容为空");
            }

            //3.操作文件对象，写入本地目录的文件中

            //3.1 截取文件后缀
            String ext = srcFile.getOriginalFilename().substring(srcFile.getContentType().lastIndexOf( ".")+1);
            //3.2 实例化目标文件，根据当前的操作系统，指定目录文件,
            destFile = new File("D:"+File.separator+"uploadfile"+File.separator+ext);
            //3.3 实例化流
            fos = new FileOutputStream(destFile);
            //3.4 获取写入的字节数组,并写入文件
            byte[] srcBytes = srcFile.getBytes();
           /* fos.write(srcBytes);
            fos.flush();
            //4.对输入、输出流进行统一管理
            //已在文件finally代码块处理

            result.put( "code", "S");
            result.put( "msg", "服务调用成功");
            result.put( "path", destFile.getAbsolutePath());*/

            String endpoint = "http://oss-cn-shanghai.aliyuncs.com";
// 阿里云主账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维，请登录 https://ram.console.aliyun.com 创建RAM账号。
            String accessKeyId = "LTAI4G95jys8AWMJgSVtSE3p";
            String accessKeySecret = "ZnaLaLRwBR68Kg6gw7xYpIySEBDTxZ";

// 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId,accessKeySecret);

            PutObjectRequest putObjectRequest = new PutObjectRequest("eyeorigin", ext,
                    new ByteArrayInputStream(srcBytes));

           /* Callback callback = new Callback();
            callback.setCallbackUrl(callbackUrl);
            callback.setCallbackHost("oss-cn-hangzhou.aliyuncs.com");
            callback.setCallbackBody("{\\\"bucket\\\":${bucket},\\\"object\\\":${object},"
                    + "\\\"mimeType\\\":${mimeType},\\\"size\\\":${size},"
                    + "\\\"my_var1\\\":${x:var1},\\\"my_var2\\\":${x:var2}}");
            callback.setCalbackBodyType(Callback.CalbackBodyType.JSON);
            callback.addCallbackVar("x:var1", "value1");
            callback.addCallbackVar("x:var2", "value2");
            putObjectRequest.setCallback(callback);
*/
// 上传Byte数组。
            //byte[] content = "Hello OSS".getBytes();
             System.out.println("upliadtime:" + System.currentTimeMillis());
            ossClient.putObject(putObjectRequest);

// 关闭OSSClient。
            ossClient.shutdown();
            System.out.println("upliadtimedonw:" + System.currentTimeMillis());

            return result;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            result = new HashMap<String,Object>();
            result.put( "code", "F");
            result.put( "msg", "服务调用失败");
            result.put( "path", null);
            return result;
        } finally{
            //关闭系统资源,避免占用资源.
            if(fos != null){
                fos.close();
            }
        }
    }

    @RequestMapping(value = "/ossCallback")
    public void ossCallback()
    {


    }


}